//  mixin/extend
// 显式混入
function mixin(source, target) {
    for (const key in source) {
        if (!(key in target)) {
            target[key] = source[key]
        }
    }
    return target
}

// 对象 不是类
const Vehicle = {
    engines: 1,
    ignition: () => {
        console.log('Turning on engines');
    },
    drive: () => {
        this.ignition();
        console.log('steering and moving forward');
    }
}

// 对象 不是类
const Car = mixin(Vehicle, {
    wheels: 4,
    drive: () => {
        // Vehicle.drive(); // this -> Vehicle
        Vehicle.drive.call(this);
        console.log(`Rolling on all: ${this.wheels}, wheels`);
    }
})
// 隐式混入
const smt = {
    cool: () => {
        this.greeting = 'hello world',
        this.count = this.count ? this.count + 1 : this.count
    }
}
smt.cool();
smt.greeting; // hello world
smt.count // 1

const ano = {
    cool: () => {
        smt.cool.call(this);
    }
}
ano.cool();
ano.greeting; // hello world
ano.count; // 1


// “类”函数
// function Foo() {}

// Foo.prototype // {} [[prototype]] -> Foo.prototype
// Foo.prototype.constructor === Foo; // true

// const a = new Foo(); // a.[[prototype]] -> Foo.prototype
// // a.constructor 本身不存在 a.constructor 通过 [[prototype]] 委托指向Foo
// a.constructor === Foo // true
// Object.getPrototypeOf(a) === Foo.prototype; // true

// Object.create();

// function NormalFunction() {
//     console.log('normal!! normal!!');
// }

// const b = new NormalFunction(); // normal!! normal!!
// console.log(b); // {}

function Foo() {}
Foo.prototype = { a: 1, b: 2 }

const a1 = new Foo();
a1.constructor === Foo // false
a1.constructor === Object // true

// 行为委托
// 类
class Task {
    id;

    Task(ID) { id = ID; }
    outputTask() { output(id); }
}

class XYZ inherits Task {
    label;

    XYZ(ID, label) { super(ID); label = label; }
    outputTask() { super(); output(label); }
}

class ABC inherits Task {
    // ...
}

// 委托
Task = {
    setID: (id) => { this.id = ID; },
    outputID: () => { console.log(this.id); }
}

XYZ = Object.create(Task);
XYZ.prepareTask = (ID, label) => {
    this.setID(ID);
    this.label = label;
}
XYZ.outputTaskDetails = () => {
    this.outputID();
    console.log(this.label);
}

function Foo()
const a1 = new Foo();
a1 // Chrome: Foo {} Firefox: Object {}
a1.constructor // Foo() {}
a1.constructor.name // Foo

Foo.prototype.constructor = function anotherFunc() {}
a1.constructor // anotherFunc() {}
a1.constructor.name // anotherFunc
a1 // Foo {}

const Foo = {}
const a2 = Object.create(Foo);
a2 //Object {}
Object.defineProperty(Foo, 'constructor', {
    enumerable: false,
    value: function anotherFunc() {}
});

a2; // Object {  }

// 面向对象&对象关联在思维模型对比
// 面向对象
function Foo(who) {
    this.me = who;
}

Foo.prototype.identity = function () {
    return `I am ${this.me}`
}

function Bar(who) {
    Foo.call(this, who);
}

Bar.prototype = Object.create(Foo.prototype);

Bar.prototype.speak = function() {
    alert(`Hello ${this.identity()} .`);
}

const b1 = new Bar('b1');
const b2 = new Bar('b2');

b1.speak();
b2.speak();

// 对象关联 [[prototype]]
Foo = {
    init: function(who) {
        this.me = who;
    },
    identity: function() {
        return `I am ${this.me}`
    }
}
Bar = Object.create(Foo);
Bar.speak = function() {
    alert(`Hello ${this.identity()}.`);
}
const b3 = Object.create(Bar);
b3.init('b3');
const b4 = Object.create(Bar);
b4.init('b4');
b3.speak(); b4.speak();


// 真实场景
// 父类
// function Widget(width, height) {
//     this.width = width || 50;
//     this.height = height || 50;
//     this.$elem = null;
// }

// Widget.prototype.render = function () {
//     if (this.$elem) {
        // this.$elem.css({
        //     width: `${this.width}px`,
        //     height: `${this.height}px`
        // }).appendTo($where);
//     }
// }
// // 子类
// function Button(width, height, label) {
//     Widget.call(this, width, height);
//     this.label = label || 'default';
//     this.$elem = $('<button>').text(this.label);
// }
// Button.prototype = Object.create(Widget.prototype);
// Button.prototype.render = function ($where) {
//     Widget.prototype.render.call(this, $where);
//     this.$elem.click(this.onClick.bind(this));
// }
// Button.prototype.onClick = function(e) {
//     console.log(`Button ${this.label} clicked!`);
// }
// $(document).ready(function() {
//     const $body = $(document.body);
//     const btn1 = new Button(125, 30, 'hello');
//     const btn2 = new Button(150, 50, 'world');
//     btn1.render($body);
//     brn2.render($body);
// })

// 对象关联
const Widget = {
    init: function(w, h) {
        this.width = width || 50;
        this.height = height || 50;
        this.$elem = null;
    },
    insert: function ($where) {
        if (this.$elem) {
            this.$elem.css({
                width: `${this.w}px`,
                height: `${this.h}px`
            }).appendTo($where);
        }
    }
}
const Button = Object.create(Widget);
Button.setup = function (w, h, l) {
    this.init(w, h);
    this.lable = l || 'default'
    this.$elem = $('<button>').text(this.label);
}
Button.build = function ($where) {
    this.insert($where);
    this.$elem.click(this.onClick.bind(this));
}
Button.onClick = function(e) {
    console.log(`Button ${this.label} clicked!`);
}
$(document).ready(function() {
    const $body = $(document.body);
    const btn1 = Object.create(Button);
    btn1.setup(120, 30, 'hello');
    const btn2 = Object.create(Button);
    btn2.setup(150, 50, 'world');
    btn1.build($body);
    brn2.build($body);
})

// 更简洁的设计
// 类设计模式
// 父类
// function Controller() {
//     this.errors = [];
// }
// Controller.prototype.showDiaglo = function (title, msg) {
//     // 显示弹窗
// }
// Controller.prototype.success = function (msg) {
//     this.showDiaglo('success', msg)
// }
// Controller.prototype.failure = function (error) {
//     this.errors.push(error)
//     this.showDiaglo('failure', err)
// }

// // 子类
// function LoginController () {
//     Controller.call(this);
// }
// LoginController.prototype = Object.create(Controller.prototype);
// LoginController.prototype.getUser = function() {
//     return document.getElementById('login_username').value;
// }
// LoginController.prototype.getPassword = function() {
//     return document.getElementById('login_password').value;
// }
// LoginController.prototype.validateEntry = function (user,pwd) {
    // user = user || this.getUser();
    // pwd = pwd || this.getPassword();
    // if (!(user && pwd)) {
    //     return this.failure('need user or pwd');
    // } else if (pwd.length < 5) {
    //     return this.failure('pwd must be 5+');
    // }
    // return true;
// }
// LoginController.prototype.failure = function (err) {
//     Controller.prototype.failure.call(this, `Login invalid: ${err}`);
// }

// // 子类
// function AuthController (login) {
//     Controller.call(this);
//     this.login = login;
// }
// AuthController.prototype = Object.create(Controller.prototype);
// AuthController.prototype.server = function (url, data) {
//     return $.ajax({ url, data });
// }
// AuthController.prototype.checkAuth = function() {
//     const user = this.login.getUser();
//     const pwd = this.login.getPassword();
//     if (this.login.validateEntry(user, pwd)) {
//         this.server('/check-auth', { user, pwd }).then(this.success.bind(this)).fail(this.failure.bind(this));
//     }
// }
// AuthController.prototype.success = function () {
//     Controller.prototype.success.call(this, 'auth access')
// }
// AuthController.prototype.failure = function (err) {
//     Controller.prototype.failure.call(this, `un auth: ${err}`);
// }

// // 继承 + 合成
// const auth = new AuthController(new LoginController());
// auth.checkAuth();

// 对象关联
const LoginController = {
    errors: [],
    getUser() {
        return document.getElementById('login_username').value;
    },
    getPassword() {
        return document.getElementById('login_password').value;
    },
    validEntry(user, pwd) {
        user = user || this.getUser();
        pwd = pwd || this.getPassword();
        if (!(user && pwd)) {
            return this.failure('need user or pwd');
        } else if (pwd.length < 5) {
            return this.failure('pwd must be 5+');
        }
        return true;
    },
    show(title, msg) {
        // 弹窗
    },
    failure(err) {
        this.errors.push(err);
        this.show('fail', `msg: ${err}`);
    }
}

// const AuthController = Object.create(LoginController);
Object.setPrototypeOf(AuthController, LoginController);
AuthController.errors = [];
AuthController.checkAuth = function() {
    const user = this.getUser();
    const pwd = this.getPassword();
    if (this.validEntry(user, pwd)) {
        this.server('/check-auth', { user, pwd }).then(this.acceptd.bind(this)).fail(this.rejected.bind(this));
    }
}
AuthController.server = function(url, data) {
    return $.ajax({ url, data });
}
AuthController.acceptd = function() {
    this.show('success', 'auth access')
}
AuthController.rejected = function() {
    this.failure(`fail, msg: ${msg}`);
}
AuthController.checkAuth();

// 反词法

var Foo = {
    bar() {},
    baz: function baz() {}
}

var Foo = {
    bar: function() {},
    baz: function baz() {}
}

const Foo = {
    bar : function (x) {
        if (x < 10) {
            return  Foo.bar(x * 2);
        }
        return x;
    },
    baz: function baz(x) {
        if (x < 10) {
            return  baz (x * 2);
        }
        return x;
    }
}

 // 内省 - 检查实例的类型

function Foo () {}
Foo.prototype.something = function () {}
const a1 = new Foo();
if (a1 instanceof Foo) {
    a1.something();
}